package com.dirven.game;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.Application.ApplicationType;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;	

public class DirVenGame implements Screen {
	
	private Game game;
	
	// Screen dimensions
	public static int screenWidth;
	public static int screenHeight;
	
	public static boolean paused;
	
	public final static int GAMESTATE_MAINMENU = 0,
							GAMESTATE_STARTSCREEN = 1,
							GAMESTATE_PREPARE = 2,
							GAMESTATE_PLAYING = 3,
							GAMESTATE_INGAME_PAUSE = 4,
							GAMESTATE_GAMEOVER = 5,
							GAMESTATE_APP_PAUSE = 6,
							GAMESTATE_APP_CLOSE = 7;
	
	public static int gameState = GAMESTATE_PLAYING;
	
	private SpriteBatch batch;
	
	public final static byte DIFFICULTY_EASY = 0,
							 DIFFICULTY_AVERAGE = 1,
							 DIFFICULTY_HARD = 2,
							 DIFFICULTY_HARDCORE = 3;
	
	private static int difficulty = DIFFICULTY_AVERAGE;

	public static Countdown stationCountdown;
	
	//private Music music;
	//private Sound sound;
	
	// Camera stuff.
	/*private OrthographicCamera camera; // The camera which will be used to look at the world.
	private Texture texture; // The texture image that will be the world map.
	private Mesh mesh; // The mesh the texture will be applied to. 
	private Mesh triangle;
	private Rectangle glViewport; // The rectangle representing the viewport.
	private float rotationSpeed; // The speed in angles with which the camera is rotated with every render call.
	*/
	
	public Grid grid;
	
	private long lastupdatedScore = 0;
	public static int score = 0;
	
	private BitmapFont font;

	
	private long stationStartTime = 0;

	private String time;
	
	public final static int PREPARATION_TIME = 3; // 3 seconds to prepare.
	private long preparationTime = PREPARATION_TIME*1000; // 3s to prepare
	private long lastTimeCheckedPreparation = 0;
	
	private IntervalTimer scoreUpdater;
	
	public static InputManager input;
	
	public DirVenGame(Game game) {
		this.game = game;
	}
	
	//@Override
	public void create() {

		Gdx.app.log("DIRVEN", "create()");
		//music = Gdx.audio.newMusic(Gdx.files.internal("data/Hans Zimmer - Time.mp3"));
		
		//sound = Gdx.audio.newSound(Gdx.files.internal("data/Punch.wav"));
		
		//music.setLooping(true);
		//music.setVolume(0.5f);
		//music.play();
		if(batch != null) {
			Gdx.app.log("DIRVEN", "removing spritebatch from prev session");
			batch.dispose();
		}
		batch = new SpriteBatch();
		
		// Get screen dimensions
		screenWidth = Gdx.app.getGraphics().getWidth();
		screenHeight = Gdx.app.getGraphics().getHeight();
		
		gameState = GAMESTATE_STARTSCREEN;
		
		font = new BitmapFont(Gdx.files.internal("data/calibri14.fnt"), Gdx.files.internal("data/calibri14.png"), false);
		scoreUpdater = new IntervalTimer(100);
	}
	
	private void restartGame() {
		// Reset the score to 0
		score = 0;
		
		// Setup the world
		setupWorld();
		
		input.reset();
		
		paused = false;
		
		// Reset the times
		stationStartTime = System.currentTimeMillis();
		// Enter the preparation game state
		gameState = GAMESTATE_PREPARE;
		// Reset the preparation time
		preparationTime = PREPARATION_TIME*1000;
		// Reset the time last checked for preparation
		lastTimeCheckedPreparation = System.currentTimeMillis();
		
		scoreUpdater = new IntervalTimer(100);
		
		stationCountdown = new Countdown(Level.getSurvivalTimeInStation(), 1000);
	}
	
	/**
	 * Restarts the game
	 */
	public void setupWorld() {
		if(grid == null) {
			// Create a grid with 5x5 pixel cells.
			grid = new Grid(5, 5);
		} else {
			// Reset the grid
			grid.reset();
		}
	}
	
	/**
	 * Sets the gamestate.
	 * @param gs
	 */
	public static void setGameState(int gs) {
		gameState = gs;
		System.out.println("GameState="+gs);
	}

	@Override
	public void dispose() {

		Gdx.app.log("DIRVEN", "Dispose()");
		// TODO Auto-generated method stub
		//music.dispose();
		//sound.dispose();
		gameState = GAMESTATE_APP_CLOSE;
	}

	@Override
	public void pause() {

		Gdx.app.log("DIRVEN", "pause()");
		paused = true;
		gameState = GAMESTATE_APP_PAUSE;
		if(stationCountdown != null) {
			stationCountdown.pause();
		}
		scoreUpdater.pause();
	}
	
	@Override
	public void render(float delta) {
		
		delta = Math.min(0.06f, Gdx.graphics.getDeltaTime());
		
		// Get graphics object
		GL10 gl = Gdx.graphics.getGL10();
		
		// Clear screen
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT/* | GL10.GL_DEPTH_BUFFER_BIT*/);
	
		//gl.glEnable(GL10.GL_TEXTURE_2D);
		
		batch.flush();
		batch.enableBlending();
		
		// Render the appropriate screen.
		switch(gameState) {
			case GAMESTATE_STARTSCREEN: renderStartScreen(batch); break;
			case GAMESTATE_PREPARE: 	renderPreparationScreen(batch); break;
			case GAMESTATE_PLAYING:		renderInGamePlaying(batch); break;
			case GAMESTATE_INGAME_PAUSE:renderInGamePause(batch); break;
			case GAMESTATE_GAMEOVER: 	renderGameOver(batch); break;
		}
		
		//batch.dispose();
		
		//gl.glFlush();
	}
	
	/**
	 * Render the preparation screen.
	 * @param batch
	 */
	public void renderPreparationScreen(SpriteBatch batch) {
		batch.begin();
		
		long currentTime = System.currentTimeMillis();
		long tDiff = currentTime - lastTimeCheckedPreparation;
		if(tDiff > 1000) {
			lastTimeCheckedPreparation = currentTime;
			// After every second, decrease the remaining preperation time by 1 second or 1000ms.
			preparationTime -= 1000;
		}
		
		// Draw text indicating the countdown.
		font.draw(batch, "Game starting in",screenWidth/2-50, screenHeight/2+15);
		font.draw(batch, ""+(preparationTime/1000),screenWidth/2-50, screenHeight/2);
		
		// If countdown is done, enter playing gamestate
		if(preparationTime <= 0) {
			stationCountdown.start();
			gameState = GAMESTATE_PLAYING;
			scoreUpdater.start();
		}
		
		batch.end();
	}
	
	/**
	 * Render the ingame pause screen
	 * @param batch
	 */
	public void renderInGamePause(SpriteBatch batch) {
		batch.begin();
		
		// Draw text indicating the countdown.
		//if(score > 0) {
		//	font.draw(batch, "Touch to resume game",screenWidth/2-50, screenHeight/2+15);
		//} else {
			font.draw(batch, "Touch to start game", screenWidth/2-50, screenHeight/2+15);
		//}
		
		if(Gdx.input.justTouched()) {
			//if(score > 0) {
			//	gameState = GAMESTATE_PLAYING;
			//	stationCountdown.resume();
			//} else {
				restartGame();
			//}
		}
		
		batch.end();
	}
	
	/**
	 * Render the game over screen
	 * @param batch
	 */
	public void renderGameOver(SpriteBatch batch) {
		batch.begin();
		font.draw(batch, "GAME OVER >:(",screenWidth/2-50, screenHeight/2+50);
		
		font.draw(batch, "Your score: "+score,screenWidth/2-50, screenHeight/2+15);
		font.draw(batch, "Your time: "+time,screenWidth/2-50, screenHeight/2);
		
		font.draw(batch, "Touch the screen to play again", screenWidth/2-100, screenHeight/2-30);
		batch.end();
		
		if(Gdx.input.justTouched()) {
			restartGame();
		}
	}
	
	public void renderStartScreen(SpriteBatch batch) {
		batch.begin();
		font.draw(batch, "DirVen Alpha Version",screenWidth/2-50, screenHeight-40);
		
		font.draw(batch, "Your goal is to last as long as possible in the station.",screenWidth/2-150, screenHeight/2+45);
		font.draw(batch, "But watch out! Don't crash into closed walls or objects.",screenWidth/2-155, screenHeight/2+30);
		font.draw(batch, "Opened walls will glow blue and only stay open for a short period of time.",screenWidth/2-210, screenHeight/2+15);
		font.draw(batch, "CONTROLS: Swipe up, down, left or right to move in that direction.",screenWidth/2-190, screenHeight/2-5);
		
		font.draw(batch, "Touch the screen to start playing", screenWidth/2-100, screenHeight/2-30);
		batch.end();
		
		if(Gdx.input.justTouched()) {
			restartGame();
		}
	}
	
	/**
	 * Render the ingame playing screen.
	 */
	public void renderInGamePlaying(SpriteBatch batch) {
		// Start drawing
		//batch.begin();
		// draw here
		
		// Update the grid
		grid.update();
		
		// Update the sore
		if(scoreUpdater.atNextInterval()) {
			score++;
		}
		
		long currentTime = System.currentTimeMillis();
		long tDiffStation = currentTime - stationStartTime;
		
		int seconds = (int) ((tDiffStation / 1000) % 60);
		int minutes = (int) ((tDiffStation / 1000) / 60);
		
		// Format time
		if(minutes > 0) {
			time = ((minutes<10)?" "+minutes:minutes)+":"+ ((seconds<10)?"0"+seconds:seconds);
		} else {
			time = ""+((seconds<10)?"0"+seconds:seconds);
		}
		
		batch.begin();
		
		// Draw the grid and all the sprites on the grid.
		grid.render(batch);
		
		// Stop drawing
		//batch.end();
		
		//batch.begin();
		//batch.enableBlending();
		font.draw(batch, "Level "+Level.getCurrentLevel(), 0, 320);
		font.draw(batch, "Score: "+score, 50, 320);
		font.draw(batch, "Time: "+time, screenWidth-160, 320);
		
		if(stationCountdown.isFinished()) {
			// Station countdown is finished.
			// Open up a random wall.
			grid.openRandomWall();
			
			// TOOD: Do tunnel stuff
			
			// Increment level
			Level.incrementLevel();
			grid.setupLevel();
			// Set new countdown
			stationCountdown = new Countdown(Level.getSurvivalTimeInStation(), 1000);
		}
		
		// Draw string of remaining time.
		font.draw(batch, stationCountdown.getRemainingTimeFormatted(), screenWidth-30, 320);
		
		// Finish drawing
		batch.end();
	}

	@Override
	public void resize(int arg0, int arg1) {
		// Get screen dimensions
		screenWidth = Gdx.app.getGraphics().getWidth();
		screenHeight = Gdx.app.getGraphics().getHeight();
	}

	@Override
	public void resume() {
		Gdx.app.log("DIRVEN", "resume()");
		
		paused = false;
		gameState = GAMESTATE_INGAME_PAUSE;
		scoreUpdater.resume();
	}

	@Override
	public void hide() {

		Gdx.app.log("DIRVEN", "hide()");
		
		if(paused) {
			Gdx.app.log("DIRVEN", "Closed app with return button.");
		}
		
		// TODO Auto-generated method stub
		if(grid != null) {
			grid.dispose();
		}
		batch.dispose();
		
		input = null;
		Gdx.input.setInputProcessor(null);
	}

	@Override
	public void show() {
		Gdx.app.log("DIRVEN", "show()");
		// TODO Auto-generated method stub
		batch = new SpriteBatch();
		
		// Get screen dimensions
		screenWidth = Gdx.app.getGraphics().getWidth();
		screenHeight = Gdx.app.getGraphics().getHeight();
		
		gameState = GAMESTATE_STARTSCREEN;
		
		font = new BitmapFont(Gdx.files.internal("data/calibri14.fnt"), Gdx.files.internal("data/calibri14.png"), false);
		scoreUpdater = new IntervalTimer(100);
	}

	/**
	 * @return the difficulty
	 */
	public static int getDifficulty() {
		return difficulty;
	}

	/**
	 * @param the difficulty setting to set
	 */
	public static void setDifficulty(int setting) {
		DirVenGame.difficulty = setting;
	}
	
	/**
	 * Check if the app is running on Android
	 * 
	 * @return true if on Android, false otherwise
	 */
	public static boolean isAndroid() {
		return (Gdx.app.getType() == ApplicationType.Android);
	}
	
	/**
	 * Check if the app is running on Desktop
	 * @return true if on desktop, false otherwise
	 */
	public static boolean isDesktop() {
		return (Gdx.app.getType() == ApplicationType.Desktop);
	}

}
 